//////////////////////////////////////////////////////////////////////////
//
// Vector Graph Core2D
//
// Module:
//        HitTest2D.cs
//
// Description:
//        Implementation of hit test operation
//
// Author:
//        Created on 2008.04.17 by Destrayer
//
//////////////////////////////////////////////////////////////////////////
using System;
using System.Collections.Generic;
using System.Text;

namespace VectorGraph.Core2D
{
    class HitTest2D
    {
        public static bool HitTest(Point2d pt, Point2d testPt, double tolerance)
        {
            return pt.Equals(testPt, tolerance);
        }

        public static bool HitTest(Rectangle2d rect, Point2d testPt, double tolerance)
        {
            // whole rectangle or just only its border?
            return testPt.X > rect.Left - tolerance && testPt.X < rect.Right + tolerance &&
                testPt.Y > rect.Bottom - tolerance && testPt.Y < rect.Top + tolerance;
        }

        public static bool HitTest(Beeline2d bl, Point2d testPt, double tolerance)
        {
            testPt -= bl.BasePt;
            double v = testPt.CrossProduct(bl.Direction);
            return v * v < tolerance * tolerance * testPt.DotProduct(testPt) * bl.Direction.DotProduct(bl.Direction);
        }

        public static bool HitTest(Circle2d c, Point2d testPt, double tolerance)
        {
            double dist = testPt.Distance(c.CenterPt);
            return dist < c.Radius + Element2D.AbsTol(c.Radius, tolerance); // circle or ring?
        }

        public static bool HitTest(Segment2d seg, Point2d testPt, double tolerance)
        {
            return testPt.X > Math.Min(seg.StartPt.X, seg.EndPt.X) - tolerance &&
                testPt.X < Math.Max(seg.StartPt.X, seg.EndPt.X) + tolerance &&
                testPt.Y > Math.Min(seg.StartPt.Y, seg.EndPt.Y) - tolerance &&
                testPt.Y < Math.Max(seg.StartPt.Y, seg.EndPt.Y) + tolerance &&
                HitTest2D.HitTest(seg.ToBeeline(), testPt, tolerance);
        }

        public static bool HitTest(Arc2d arc, Point2d testPt, double tolerance)
        {
            if (HitTest2D.HitTest(arc.ToCircle(), testPt, tolerance))
            {
                double angle = arc.StartVector.SweepAngle(testPt - arc.CenterPt);
                return angle < arc.SweepAngle + tolerance || angle > 2 * Math.PI - tolerance;
            }
            return false;
        }

        public static bool HitTest(Path2d path, Point2d testPt, double tolerance)
        {
            foreach (Segment2d seg in path.Edges)
            {
                if (HitTest2D.HitTest(seg, testPt, tolerance))
                {
                    return true;
                }
            }
            return false;
        }
    }
}
